use anyhow::Result;
use chrono::Utc;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryOrder,
    QueryFilter, Set,
};

use crate::entity::reservation::{self, Entity as Reservation, Model as ReservationModel};
use crate::grpc::reservation::{Reservation as GrpcReservation, ReservationStatus};

pub struct ReservationService {
    db: DatabaseConnection,
}

impl ReservationService {
    pub fn new(db: DatabaseConnection) -> Self {
        Self { db }
    }

    /// 创建新的预订
    pub async fn create_reservation(
        &self,
        guest_name: String,
        guest_email: String,
        guest_phone: String,
        room_number: String,
        check_in_date: chrono::NaiveDate,
        check_out_date: chrono::NaiveDate,
        total_amount: f64,
    ) -> Result<ReservationModel> {
        let reservation = reservation::ActiveModel {
            guest_name: Set(guest_name),
            guest_email: Set(guest_email),
            guest_phone: Set(guest_phone),
            room_number: Set(room_number),
            check_in_date: Set(check_in_date),
            check_out_date: Set(check_out_date),
            status: Set("PENDING".to_string()),
            total_amount: Set(total_amount),
            created_at: Set(Utc::now().naive_utc()),
            updated_at: Set(Utc::now().naive_utc()),
            ..Default::default()
        };

        let reservation = reservation.insert(&self.db).await?;
        Ok(reservation)
    }

    /// 根据ID获取预订
    pub async fn get_reservation(&self, id: i32) -> Result<Option<ReservationModel>> {
        let reservation = Reservation::find_by_id(id).one(&self.db).await?;
        Ok(reservation)
    }

    /// 更新预订状态
    pub async fn update_reservation_status(&self, id: i32, status: ReservationStatus) -> Result<Option<ReservationModel>> {
        let reservation = Reservation::find_by_id(id).one(&self.db).await?;
        
        if let Some(reservation) = reservation {
            let mut active_model: reservation::ActiveModel = reservation.into();
            active_model.status = Set(ReservationModel::to_status_str(status));
            active_model.updated_at = Set(Utc::now().naive_utc());
            
            let updated = active_model.update(&self.db).await?;
            Ok(Some(updated))
        } else {
            Ok(None)
        }
    }

    /// 列出预订，支持分页和过滤
    pub async fn list_reservations(
        &self,
        page: u64,
        per_page: u64,
        guest_name: Option<String>,
        room_number: Option<String>,
        status: Option<String>,
    ) -> Result<(Vec<ReservationModel>, u64)> {
        let mut query = Reservation::find().order_by_asc(reservation::Column::Id);

        if let Some(name) = guest_name {
            query = query.filter(reservation::Column::GuestName.contains(&name));
        }

        if let Some(room) = room_number {
            query = query.filter(reservation::Column::RoomNumber.contains(&room));
        }

        if let Some(status) = status {
            query = query.filter(reservation::Column::Status.eq(&status));
        }

        let paginator = query.paginate(&self.db, per_page);
        let total = paginator.num_items().await?;
        let reservations = paginator.fetch_page(page - 1).await?;

        Ok((reservations, total))
    }

    /// 取消预订
    pub async fn cancel_reservation(&self, id: i32, reason: String) -> Result<Option<ReservationModel>> {
        // 在实际应用中，这里可以记录取消原因
        let _ = reason;
        self.update_reservation_status(id, ReservationStatus::Cancelled).await
    }

    /// 将实体模型转换为gRPC模型
    pub fn model_to_grpc(model: ReservationModel) -> GrpcReservation {
        GrpcReservation {
            id: model.id.to_string(),
            guest_name: model.guest_name,
            guest_email: model.guest_email,
            guest_phone: model.guest_phone,
            room_number: model.room_number,
            check_in_date: model.check_in_date.to_string(),
            check_out_date: model.check_out_date.to_string(),
            status: ReservationModel::from_status_str(&model.status).into(),
            total_amount: model.total_amount,
            created_at: model.created_at.to_string(),
            updated_at: model.updated_at.to_string(),
        }
    }
}